#ifndef __WATCHER_H_INCLUDED__
#define __WATCHER_H_INCLUDED__

#include "json.h"
#include <ctime>
#include <functional>

#if defined(_WIN32)
#include <Windows.h>
#endif

#define GWatcher Watcher::Instance()

class Watcher {
public:
  enum EStatus {
    Stopped = 0,
    Running = 1,
    Fatal = 2,
    Retry = 3,
  };

  typedef struct Info {
    EStatus emStatus;
#if defined(_WIN32)
    HANDLE hPipe;
    DWORD nPid;
    LONGLONG nLastCalcCPU;
    LONGLONG nLastCPUTotal;
#else
    int nFd;
    int nPid;
#endif
    char pTail[16384];
    int nTail;
    int nRetry;
    std::string sCmd;
    std::string sPath;
    time_t nStart;

    Info()
        : emStatus(EStatus::Stopped), nPid(-1), pTail{0}, nTail(0), nRetry(0),
          sCmd(), sPath(), nStart(0) {}
    std::string GetStartTime() const {
      if (nStart == 0)
        return "----";

      struct tm *pLocal = NULL;
#if defined(_WIN32)
      struct tm iLocal = {0};
      pLocal = &iLocal;
      localtime_s(pLocal, &nStart);
#else
      pLocal = localtime(&nStart);
#endif

      char pBuf[32] = {0};
      strftime(pBuf, 32, "%F %T", pLocal);
      return std::string(pBuf);
    }
  } Info;

  typedef std::function<void(const std::string &, const Json::Value &)>
      Notifier;

public:
  Watcher() {}

  static Watcher &Instance();

  void SetNotifier(Notifier fNotifier) { _fNotifier = fNotifier; }
  void Breath();

  void Start(const std::string &sName, const std::string &sPath,
             const std::string &sCmd, int nRetry);
  void Stop(const std::string &sName);
  void StopAll();
  void Remove(const std::string &sName);
  Info *Get(const std::string &sName);

private:
  void Notify(const std::string &sScope, const Json::Value &rMsg);
  void Tail(const std::string &sName, Info &rInfo);
  void AppendTail(const std::string &sName, Info &rInfo,
                  const std::string &sTail);
  void CatchExit(const std::string &sName, Info &rInfo, EStatus emStatus,
                 bool bRetry = false);

private:
  std::map<std::string, Info> _mWatcher;
  Notifier _fNotifier;
};

#endif //!	__WATCHER_H_INCLUDED__